#!/bin/bash
#VERSION="1.06"
#support multi devices.
#VERSION="1.07"
#when usb re-attach happen, disable usb log and cp aplog to sdcard and download it.
#because it's maybe make log lose. 
#VERSION="1.08"
#change verdor and product id for intel product
#VERSION="1.09"
#change  
#find_adb_devices=`$adb devices | grep "$OPT"`
#to
#find_adb_devices=`$adb devices | grep "$OPT.*device"`
#it's more detail information we can got.  
#VERSION="1.0A"
#add adb get-state, to check usb state  
#VERSION="1.0B"
#change `adb get-state` twice to onece. because perhaps the two times is different.
#VERSION="1.0C"
#backup device time, because the device time is different with PC in second.
#VERSION="1.0D"
#add
#1. if it's only one device, it's not needed to input -s option
#2. add backup adb log
#VERSION="1.0E"
#add some judgement in script
#VERSION="1.0F"
#1. Get device adb log is depend on ptr, get PC adb log all the time. 
#2. after the issue happen, disable all usb log before do anything. 
#VERSION="1.10"
#1. backup adb log to home folder before echo 0 > adb.log.
#VERSION="1.11"
#1. add some note.
#2. add judgement on adb.log.before file.
#VERSION="1.12"
#1. fix multi devices with one adb_log folder issue. 
#VERSION="1.13"
#1. add syslog file to equivalent PC dmesg time with date time. 
#2. fix multi device lsusb -s display show wrong device error. 
#3. add ehci-hcd.c log enabling.
#4. add workaround for adb shell no reaction.
#5. add sleep 1 in main loop.
#VERSION="1.14"
#1. add workaroud to avoid "disable stream mode" patch, mantis 31948(R3)
VERSION="1.15"
#1. fix multi device, lsusb get wrong bus address issue. 

vendor=8087
product=09fc
lsusb="lsusb -d $vendor:$product"
line=`$lsusb | awk '{print NR}' | tail -n1`
log_path=/sys/kernel/debug/dynamic_debug/control
n=1
EnableDevicesAdbLog=0
#log file count
log_file_count=1
adb_log=0
usb_bus=0
usb_device=0
no_reaction=0

function usage () {
    echo "-s option to set serial number"
    echo "-t option to run listenning process"
    echo "-h option for more information"
    echo "-e option to enable log"
    echo "-n option to workaround adb shell no reaction issue"
    echo "example:"
    echo "\$adb devices"
    echo "List of devices attached"
    echo "0123456789ABCDE        device"
    echo "`basename $0` -s 0123456789ABCDE"
    exit 0
}

function contect_append () {
    echo -e "$1" >> $backup_file;
}

function debug_script () {
    echo "$1" 
    #echo -n "" 
}

function enable_usb_log () {
    $adb shell "echo -n 'file langwell_udc.c +p' > $log_path"
    $adb shell "echo -n 'file penwell_otg.c +p' > $log_path"
    $adb shell "echo -n 'file composite.c +p' > $log_path"
    $adb shell "echo -n 'file android.c +p' > $log_path"
    $adb shell "echo -n 'file f_adb.c +p' > $log_path"
    $adb shell "echo -n 'file ehci-hcd.c +p' > $log_path"
}

function disable_usb_log () {
    $adb shell "echo -n 'file langwell_udc.c -p' > $log_path"
    $adb shell "echo -n 'file penwell_otg.c -p' > $log_path"
    $adb shell "echo -n 'file composite.c -p' > $log_path"
    $adb shell "echo -n 'file android.c -p' > $log_path"
    $adb shell "echo -n 'file f_adb.c -p' > $log_path"
    $adb shell "echo -n 'file ehci-hcd.c -p' > $log_path"
}

function backup_log () {
    DATE=`date "+%Y.%m%d.%H%M%S"`
    disable_usb_log
    contect_append "usb re-connect time `date`\n"
    contect_append "$adb shell ps info:\n`$adb shell ps`\n"
    contect_append "pc ps info:\n`ps aux`\n\n"
    contect_append "pc dmesg info:\n`dmesg`\n\n"
    contect_append "pc syslog info:\n`cat /var/log/syslog`\n\n"
    sleep 4
    $adb shell "mkdir /sdcard/logs"
    debug_script "cp data"
    $adb shell "cp /data/logs/aplog* /sdcard/logs/" 
    debug_script "pull aplogs"
    $adb pull /sdcard/logs ./$OPT-usb-disconnected-$DATE
    mv $backup_file ./$OPT-usb-disconnected-$DATE/

    if [ "$EnableDevicesAdbLog" == "0xF" ];
    then
	$adb shell "mkdir /sdcard/adblogs"
	$adb shell "cp /data/adb/* /sdcard/adblogs/" 
	$adb pull /sdcard/adblogs ./$OPT-usb-disconnected-$DATE
    fi

    cp /tmp/adb.log ./$OPT-usb-disconnected-$DATE/adb.pc.log
    if [ -e /tmp/adb.log.before ];
    then
        cp /tmp/adb.log.before ./$OPT-usb-disconnected-$DATE/adb.pc.log.before
    fi
    hardware_issue=`grep -r "ulpi read time out by polling" ./$OPT-usb-disconnected-$DATE/`

    if [ "$hardware_issue" != "" ];
    then
	contect_append "$hardware_issue"
	echo "$hardware_issue"
	echo "this issue is hardware issue perhaps."
	echo "if the log time is close to the issue happen time."
	echo "("
	echo "log time - issue happen time < 3mins "
	echo "issue happen time - log time < 3mins "
	echo ")"
	echo "you can make sure is hardware issue."
    fi
}

function match_usb_devices () {
    i=1
    while (($i <= $line))
    do
	debug_script "i: $i, line: $line"
	usb_bus="`$lsusb | awk NR==$i | awk '{print $2}'`"
	debug_script "usb_bus: $usb_bus"
	usb_device="`$lsusb | awk NR==$i | awk '{print $4}'`"
	debug_script "usb_device: $usb_device"
	adb_iserial=`$lsusb -s $usb_bus:$usb_device -v | grep iSerial | awk '{print $3}'`
	debug_script "adb_iserial: $adb_iserial"
	if [ "$adb_iserial" == "$OPT" ];
	then
	    debug_script "adb_iserial == $OPT"
	    break
	fi
	i=`expr $i + 1`
    done
}

function creat_adb_log_folder () {
    adb_log=adb_log-$1
    if [ -e ~/$adb_log ];
    then
	echo "you have $adb_log folder in home folder."
	echo "Do you want to clean log folder which is created on last time ?, input Y/N"
	read clear_value
	if [ "$clear_value" == "Y" -o "$clear_value" == "y" ]; 
	then
	    rm -rf ~/$adb_log
	else
	    echo "abort process, please handle the log first."
	    exit 0
	fi
    fi
    mkdir ~/$adb_log
}

function workaround_usbdevfs () {
    $adb shell cat /sys/devices/pci0000:00/0000:00:02.3/registers | grep USBMODE

    $adb shell "echo 0 > /sys/devices/pci0000:00/0000:00:02.3/sdis"
    echo "please remember do detach and attach usb cable again after this step."
    echo "please remember do not change 'mtp to ptp' or 'enable or disable adb' after this step."
    echo "you can check whether successful by"
    echo "$adb shell cat /sys/devices/pci0000:00/0000:00:02.3/registers | grep USBMODE"
    echo "if success, bit 4 of usbmode register will be set 0."
    exit 0
}

function init () {
    while getopts "s:thenw" opt; do
	case $opt in
	    s) OPT=$OPTARG;;
	    t) test="1";;
	    e) enable_log="1";;
	    n) no_reaction="1";;
	    w) wa_usbdevfs="1";;
	    h) usage; exit 1;;
	esac
    done

    debug_script "1. \$# = $#"
    if [ "$#" == "0" ]; 
    then
	echo "Try '$0 -h' for more information" 
	exit 0
    fi

    if [ "$OPT" == "" ];
    then
	devices_number=`adb devices | grep "Medfield.*" | awk '{print $1}' | wc -l`
	if [ "$devices_number" == "1" ];then
            OPT=`adb devices | grep "Medfield.*" | awk '{print $1}' | awk NR==1`
        else
	    echo "Try '$0 -h' for more information"
	    exit 0
        fi
    fi
    debug_script "2. OPT = $OPT"

    adb="adb -s $OPT"
    EnableDevicesAdbLog=`$adb shell "getprop persist.adb.trace_mask" | cut -b1-3`
    DATE=`date "+%Y.%m%d.%H%M%S"`
    backup_file=usb-info-$OPT-$DATE.txt

    if [ "$enable_log" == "1" ];
    then
	enable_usb_log

	if [ "$EnableDevicesAdbLog" == "0xF" ];
	then
        #if we want to debug usb, we need enable both PC and Device side log.
            creat_adb_log_folder $OPT
	fi
    fi

    if [ "$wa_usbdevfs" == "1" ];
    then
	workaround_usbdevfs "$wa_usbdevfs"
    fi

}

function begin_test () {
    debug_script "3. begin test."
    match_usb_devices
    PCStartTime="PC  start time: `date`"
    echo "$PCStartTime"
    contect_append "$PCStartTime"

    DUTStartTime="DUT start time: `$adb shell date`"
    echo "$DUTStartTime"
    contect_append "$DUTStartTime"

    #get DUT ps info before test.
    contect_append "$adb shell ps info:\n`$adb shell ps`\n"
    #get pc dmesg info before test.
    contect_append "pc ps info:\n`ps aux`\n\n"
    contect_append "pc dmesg | tail info:\n`dmesg | tail`\n\n"
    contect_append "pc syslog | tail info:\n`cat /var/log/syslog | tail`\n\n"
    contect_append "$lsusb info:\n`$lsusb -s $usb_bus:$usb_device`"
}


function cut_adb_pc_log () {
    size=`cat /tmp/adb.log | wc -c`
    #keep adb.log size isn't too big. 
    if (( "$size" >= "17830039" ))
    then
	cp -rf /tmp/adb.log /tmp/adb.log.before
	echo 0 > /tmp/adb.log
	7z a ~/$adb_log/adb.log.$log_file_count.7z /tmp/adb.log.before > /dev/null
	log_file_count=`expr $log_file_count + 1`
    fi
}

time_before=0
time_after=0
function no_reaction_workaround () {
    if [ "$no_reaction" == "1" ];
    then
	if [ "$time_before" == "0" ];
	then
	    time_before=`date +%s`
	    debug_script "time_before=$time_before"
	    return;
	fi

	time_after=`date +%s`
	debug_script "time_after=$time_after"

	btw=`expr $time_after - $time_before`
	if [[ "$btw" -ge "10" ]];
	then
	    $lsusb -s $usb_bus:$usb_device -v > /dev/null
	    time_before=0
	    time_after=0

	fi
    fi
}

function main () {

	echo "script version $VERSION"
	init $@
	debug_script "4. test: $test"
	if [ "$test" == "1" ];
	then
	    begin_test
	fi

	debug_script "5. testing..."
	while [ "$test" == "1" ]
	do
	    find_adb_devices=`$adb devices | grep "$OPT.*device"`
	    find_usb_devices=`$lsusb -s $usb_bus:$usb_device`

            if [ "$n" == "1" ];
            then
		get_state=`$adb get-state`
		if [ "$get_state" != "device" ];
		then
                    echo " warning: on `date`, adb device state is $get_state"
                    n=0
		fi
            fi

	    cut_adb_pc_log
	    sleep 1
	    no_reaction_workaround

            if [ "$find_adb_devices" == "" -o "$find_usb_devices" == "" ];
            then
		echo "usb disconnected time `date`"
		contect_append "usb disconnected time `date`\n"
		contect_append "find_adb_devices: `$adb devices`"
		contect_append "pc syslog info:\n`cat /var/log/syslog`\n\n"
		contect_append "pc dmesg info:\n`dmesg`\n\n"

            #if adb re-enum and connected, we get log
		while true
		do
                    find_adb_devices=`$adb devices | grep "$OPT.*device"`
                    if [ "$find_adb_devices" != "" ];
                    then
			echo "usb re-connect time `date`"
			echo "ready to download log"
			backup_log
			exit 0
                    fi
		done
            fi
	done
    }

main $@
